package capaPresentacion.client.presentador;

import java.util.Date;
import java.util.List;

import capaPresentacion.client.WorldsTrainerWebServiceAsync;
import capaPresentacion.client.evento.EventoLogout;
import capaPresentacion.client.evento.EventoLogueoUsuario;
import capaPresentacion.shared.ComentarioDTO;
import capaPresentacion.shared.InfoRutaDTO;
import capaPresentacion.shared.RutaDTO;
import capaPresentacion.shared.RutaFicheroDTO;
import capaPresentacion.shared.UsuarioDTO;
import capaPresentacion.shared.Verificador;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.Widget;

public class PresentadorUsuario implements Presentador {

	public interface Display {

		Widget asWidget();

		MenuItem verMisAmigos();

		MenuItem verMisRutas();

		MenuItem logout();

		MenuItem modificarDatos();

		HasClickHandlers botonVerAmigo();

		HasClickHandlers botonVerInfoRutaCompleta();

		HasClickHandlers botonPublicarComentario();

		HasClickHandlers aceptarModificacionDatos();

		HasClickHandlers botonDarBaja();

		HasClickHandlers botonBuscarDialogoUsuario();

		HasClickHandlers botonBuscarDialogoRuta();

		HasClickHandlers botonMostrarRuta();

		HasClickHandlers botonHacerAmigo();

		HasClickHandlers botonEliminarAmigo();

		HasValue<String> areaComentario();

		HasValue<String> getNombre();

		HasValue<String> getApellidos();

		HasValue<String> getEmail();

		HasValue<String> getContrasenya1();

		HasValue<String> getContrasenya2();

		HasValue<String> getPeso();

		HasValue<String> getAltura();

		HasValue<String> getEdad();

		HasValue<String> getNombreUsuarioBusqueda();

		HasValue<String> getNombreRutaBusqueda();

		String idAmigo();

		long idRuta();

		long idInfo();
		
		boolean comentarioInfoRuta();

		void mostrarRutas(List<InfoRutaDTO> infoRutaDTO);

		void mostrarMisAmigos(List<UsuarioDTO> amigos);

		void mostrarInfoRutaCompleta(RutaFicheroDTO infoRuta);

		void buscarUsuario(List<UsuarioDTO> usuariosDTO,
				List<UsuarioDTO> amigos, String emailUsuario);

		void buscarRuta(List<RutaDTO> rutasDTO);

		void mostrarRuta(RutaFicheroDTO result);

		void resetAreaComentario();

		void mostrarComentariosDeRuta(List<ComentarioDTO> comentarios);

		void verModificarDatos(UsuarioDTO usuario);
	}

	private final WorldsTrainerWebServiceAsync rpcService;
	private final HandlerManager eventBus;
	private final Display display;

	public PresentadorUsuario(WorldsTrainerWebServiceAsync rpcService,
			HandlerManager eventBus, Display display) {
		this.rpcService = rpcService;
		this.eventBus = eventBus;
		this.display = display;
		bind();
	}

	@Override
	public void go(HasWidgets container) {
		container.clear();
		container.add(display.asWidget());
	}

	private void bind() {
		this.display.verMisRutas().setCommand(new Command() {

			@Override
			public void execute() {
				doObtenerInfoRutas();
			}
		});
		this.display.verMisAmigos().setCommand(new Command() {

			@Override
			public void execute() {
				doObtenerMisAmigos();
			}
		});
		this.display.logout().setCommand(new Command() {

			@Override
			public void execute() {
				doLogout();
			}
		});
		this.display.botonVerInfoRutaCompleta().addClickHandler(
				new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						doMostrarInfoRutaCompleta();
					}
				});
		this.display.botonVerAmigo().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				doMostrarInfoRutasAmigo();
			}
		});
		this.display.botonBuscarDialogoRuta().addClickHandler(
				new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						doMostrarBusquedaRutas();
					}
				});
		this.display.botonBuscarDialogoUsuario().addClickHandler(
				new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						doMostrarBusquedaUsuarios();
					}
				});
		this.display.botonHacerAmigo().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				doHacerAmigo();
			}
		});
		this.display.botonMostrarRuta().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				doMostrarRuta();
			}
		});
		this.display.modificarDatos().setCommand(new Command() {

			@Override
			public void execute() {
				doVerModificarDatos();
			}
		});
		this.display.aceptarModificacionDatos().addClickHandler(
				new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						doModificarDatos();
					}
				});
		this.display.botonDarBaja().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				doDarseBaja();
			}
		});
		this.display.botonEliminarAmigo().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				doEliminarAmigo();
			}
		});
		this.display.botonPublicarComentario().addClickHandler(
				new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						doPublicarComentario();
					}
				});
	}

	protected void doPublicarComentario() {
		String comentario = display.areaComentario().getValue();
		if (!comentario.equals("")) {
			rpcService.hacerComentarioDTO(comentario, new Date(),
					display.idRuta(), new AsyncCallback<Void>() {

						@Override
						public void onSuccess(Void result) {
							display.resetAreaComentario();
							if (display.comentarioInfoRuta()) {
								doMostrarInfoRutaCompleta();
							} else
								doMostrarRuta();
						}

						@Override
						public void onFailure(Throwable caught) {
							Window.alert("Error publicando comentario");
						}
					});
		} else
			Window.alert("No ha introducido texto en el comentario");
	}

	protected void doEliminarAmigo() {
		rpcService.quitarAmigo(display.idAmigo(), new AsyncCallback<Void>() {

			@Override
			public void onSuccess(Void result) {
				doObtenerMisAmigos();
			}

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error eliminando amistad");
			}
		});
	}

	protected void doDarseBaja() {
		rpcService.darseBaja(new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error al dar de baja");
			}

			@Override
			public void onSuccess(Void result) {
				eventBus.fireEvent(new EventoLogout());
			}
		});
	}

	protected void doVerModificarDatos() {
		rpcService.obtenerUsuario(new AsyncCallback<UsuarioDTO>() {

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error al recuperar los datos");
			}

			@Override
			public void onSuccess(UsuarioDTO result) {
				display.verModificarDatos(result);
			}
		});
	}

	protected void doModificarDatos() {
		String email = display.getEmail().getValue();
		String contrasenya = display.getContrasenya1().getValue();
		String nombre = display.getNombre().getValue();
		String apellidos = display.getApellidos().getValue();
		String peso = display.getPeso().getValue();
		String altura = display.getAltura().getValue();
		String edad = display.getEdad().getValue();
		if (Verificador.esEmailValido(email)
				&& Verificador.esContrasenyaValida(contrasenya)
				&& Verificador.esNombreApellidoValido(nombre)
				&& Verificador.esNombreApellidoValido(apellidos)
				&& Verificador.esEdadValida(edad)
				&& Verificador.esAlturaValida(altura)
				&& Verificador.esPesoValido(peso)) {
			if (contrasenya.equals(display.getContrasenya2().getValue())) {
				rpcService.modificarUsuario(
						new UsuarioDTO(email, nombre, apellidos, contrasenya,
								Integer.parseInt(edad), Float.parseFloat(peso),
								Integer.parseInt(altura)),
						new AsyncCallback<Void>() {

							@Override
							public void onSuccess(Void result) {
								eventBus.fireEvent(new EventoLogueoUsuario());
							}

							@Override
							public void onFailure(Throwable caught) {
								Window.alert("Error al modificar los datos");
							}
						});
			} else
				Window.alert("Las contraseñas introducidas no son iguales");
		}
	}

	protected void doMostrarRuta() {
		final long idRuta = display.idRuta();
		if (idRuta != -1) {
			rpcService.obtenerDatosRuta(idRuta,
					new AsyncCallback<RutaFicheroDTO>() {

						@Override
						public void onSuccess(RutaFicheroDTO result) {
							display.mostrarRuta(result);
							rpcService.obtenerComentariosRuta(idRuta,
									new AsyncCallback<List<ComentarioDTO>>() {

										@Override
										public void onSuccess(
												List<ComentarioDTO> result) {
											display.mostrarComentariosDeRuta(result);
										}

										@Override
										public void onFailure(Throwable caught) {
											Window.alert("Error recuperando comentarios de ruta");
										}
									});
						}

						@Override
						public void onFailure(Throwable caught) {
							Window.alert("Error al mostrar la ruta");
						}
					});
		}
	}

	protected void doHacerAmigo() {
		String emailAmigo = display.idAmigo();
		if (!emailAmigo.equals("Ninguno")) {
			rpcService.hacerAmigo(emailAmigo, new AsyncCallback<Void>() {

				@Override
				public void onSuccess(Void result) {
					doMostrarBusquedaUsuarios();
				}

				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Error al realizar la amistad");
				}
			});
		}

	}

	protected void doMostrarBusquedaUsuarios() {
		String cadena = display.getNombreUsuarioBusqueda().getValue();
		if (!cadena.equals("")) {
			rpcService.buscarUsuariosDTO(cadena,
					new AsyncCallback<List<UsuarioDTO>>() {

						@Override
						public void onSuccess(final List<UsuarioDTO> result) {
							rpcService
									.obtenerAmigosDTO(new AsyncCallback<List<UsuarioDTO>>() {

										@Override
										public void onSuccess(
												final List<UsuarioDTO> amigos) {
											rpcService
													.obtenerEmailUsuario(new AsyncCallback<String>() {

														@Override
														public void onSuccess(
																String emailUsuario) {
															display.buscarUsuario(
																	result,
																	amigos,
																	emailUsuario);
														}

														@Override
														public void onFailure(
																Throwable caught) {
															Window.alert("Error al realizar la busqueda de usuarios");
														}
													});
										}

										@Override
										public void onFailure(Throwable caught) {
											Window.alert("Error al realizar la busqueda de usuarios");
										}
									});
						}

						@Override
						public void onFailure(Throwable caught) {
							Window.alert("Error al realizar la busqueda de usuarios");
						}
					});
		} else
			Window.alert("No ha introducido texto a buscar");
	}

	protected void doMostrarBusquedaRutas() {
		String cadena = display.getNombreRutaBusqueda().getValue();
		if (!cadena.equals("")) {
			rpcService.buscarRuta(cadena, new AsyncCallback<List<RutaDTO>>() {

				@Override
				public void onSuccess(List<RutaDTO> result) {
					display.buscarRuta(result);
				}

				@Override
				public void onFailure(Throwable caught) {
					Window.alert("Error al realizar la busqueda de rutas");
				}
			});
		} else
			Window.alert("No ha introducido texto a buscar");
	}

	protected void doMostrarInfoRutaCompleta() {
		long info = display.idInfo();
		if (info != -1) {
			rpcService.obtenerInfoRuta(info,
					new AsyncCallback<RutaFicheroDTO>() {

						@Override
						public void onSuccess(RutaFicheroDTO result) {
							display.mostrarInfoRutaCompleta(result);
							rpcService.obtenerComentariosRuta(result.getRuta()
									.getId(),
									new AsyncCallback<List<ComentarioDTO>>() {

										@Override
										public void onSuccess(
												List<ComentarioDTO> result) {
											display.mostrarComentariosDeRuta(result);
										}

										@Override
										public void onFailure(Throwable caught) {
											Window.alert("Error recuperando comentarios de ruta");
										}
									});
						}

						@Override
						public void onFailure(Throwable caught) {
							Window.alert("Fallo al obtener informacion de la ruta");
						}
					});
		}
	}

	protected void doMostrarInfoRutasAmigo() {
		if (!display.idAmigo().equals("Ninguno")) {
			rpcService.obtenerInfoRutasUsuarioAmigo(display.idAmigo(),
					new AsyncCallback<List<InfoRutaDTO>>() {

						@Override
						public void onSuccess(List<InfoRutaDTO> result) {
							display.mostrarRutas(result);
						}

						@Override
						public void onFailure(Throwable caught) {
							Window.alert("Fallo al obtener informacion de la ruta del amigo");
						}
					});
		}
	}

	protected void doLogout() {
		rpcService.logout(new AsyncCallback<Void>() {

			@Override
			public void onSuccess(Void result) {
				eventBus.fireEvent(new EventoLogout());
			}

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error al salir");
			}
		});
	}

	protected void doObtenerMisAmigos() {
		rpcService.obtenerAmigosDTO(new AsyncCallback<List<UsuarioDTO>>() {

			@Override
			public void onSuccess(List<UsuarioDTO> result) {
				display.mostrarMisAmigos(result);
			}

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error obteniendo los amigos");
			}
		});
	}

	protected void doObtenerInfoRutas() {
		rpcService.obtenerInfoRutasDTO(new AsyncCallback<List<InfoRutaDTO>>() {

			@Override
			public void onSuccess(List<InfoRutaDTO> result) {
				display.mostrarRutas(result);
			}

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Error obteniendo los datos de la ruta");
			}
		});
	}
}
